import { message } from '@/components/basic/message';
import { DefaultService as Api, DefaultService } from '@/servers';
import { getValue } from '@/utils/get';
import { ElMessageBox } from 'element-plus';
import { onMounted, reactive, Ref, ref, ToRefs } from 'vue';

export type InitTableOptions<T> = {
  query: StaticMethodNames<T>;
  getParams?: () => MethodArgs<T, StaticMethodNames<T>>;
  [key: string]: any;
};

export const generateGetParams: (...args: any[]) => () => any[] = (...args) => {
  return () => args;
};

const defaultOptions: InitTableOptions<typeof DefaultService> = {
  query: 'getSystemMenuList',
  getParams: (...args) => args
};

export type StaticMethodNames<T> = {
  [K in keyof T]: T[K] extends (...args: any[]) => any ? K : never;
}[keyof T];

type MethodArgs<T, K extends StaticMethodNames<T>> = T[K] extends (...args: infer A) => any ? [...A] : never;

/**
 * @description 获取表格数据
 * @param {object} options 配置项
 * @param {boolean} isInit 是否初始化
 * @returns
 */
export const useTableData = (
  options: InitTableOptions<typeof DefaultService> = defaultOptions,
  isInit: boolean = true
) => {
  const tableData = ref<any[]>([]);
  const loading = ref(false);

  const fetchData = async () => {
    loading.value = true;
    try {
      // @ts-ignore
      const res = await Api[options.query](...options.getParams());

      // 直接替换 tableData 的值，确保 Vue 响应数据变化
      tableData.value = getValue(res, options.listUrl || 'data', []);
    } catch (error) {
      console.error('Error fetching data:', error);
    } finally {
      options.sort && tableData.value.sort(options.sort);
      loading.value = false;
    }
  };

  if (isInit) {
    onMounted(() => {
      !tableData.value.length && fetchData();
    });
  }

  return {
    tableData,
    loading,
    fetchData
  };
};

function getParams(origin: any, list: string[], paramType: 'params' | 'formData') {
  if (paramType === 'formData') {
    const params = {};
    list.forEach(urls => {
      const key = urls.split('.').pop();
      params[key as string] = getValue(origin, urls, '');
    });
    return params;
  }

  return list.map(urls => {
    const result = getValue(origin, urls, '');
    // 判断 result 是否是对象或数组，如果是则转换为 JSON 字符串
    // if (typeof result === 'object') {
    //   return JSON.stringify(result);
    // }
    return result;
  });
}

/**
 * @description 获取表格数据
 * @param {object} options 配置项
 * @returns
 */
export const useTable: (options: TableOptions) => resultOptions = (options: TableOptions) => {
  const defaultOptions = {
    isInit: true,
    data: [],
    query: 'getSystemMenuList',
    delete: '',
    loading: false,
    Params: [],
    paramType: 'params',
    page: 1,
    pageSize: 10,
    total: 0,
    sort: (a: any, b: any) => b - a
  };

  const isPagniation = options.listUrl ? true : false;

  // 这里的合并后应该返回 props⭐⭐⭐
  const mergeState = (options: IObject, props: IObject) => {
    Object.keys(options).forEach(key => !Reflect.has(props, key) && (props[key] = options[key]));
    return props;
  };

  const state = mergeState(defaultOptions, options) as TableOptions;

  const fetchData = async () => {
    state.loading = true;
    try {
      let res: any = {};
      if (state.paramType === 'params') {
        // @ts-ignore
        res = await Api[state.query](...getParams(state, state.Params));
      } else {
        res = await Api[state.query](getParams(state, state.Params!, state.paramType!));
      }

      // 直接替换 tableData 的值，确保 Vue 响应数据变化
      state.data = getValue(res, state.listUrl || 'data', [])?.filter((i: IObject) => i);

      isPagniation && (state.total = Number(getValue(res, 'data.total', 0)));
    } catch (error) {
      console.error('Error fetching data:', error);
    } finally {
      state.sort && state.data.sort(state.sort);
      state.loading = false;
    }
  };

  const editRowItem = async (row: any) => {
    state.openEdit && state.openEdit(row);
  };

  const deleteRowItem = async (row: any) => {
    ElMessageBox.confirm('sure delete this item?', 'Tip', {
      confirmButtonText: 'confirm',
      cancelButtonText: 'cancel',
      type: 'warning'
    }).then(async () => {
      if (state.delete) {
        // @ts-ignore
        await Api[state.delete](row.id);
        await fetchData();
      }
    });
  };

  const selectionChange = (val: any) => {
    state.multiple = val;
  };

  const pageCurrentChangeHandle = (val: number) => {
    state.page = val;
    fetchData();
  };

  if (options.isInit) {
    onMounted(() => {
      !state.data.length && fetchData();
    });
  }

  return {
    fetchData,
    deleteRowItem,
    editRowItem,
    selectionChange,
    pageCurrentChangeHandle,
    ...state
  };
};

type TableOptions = {
  isInit?: boolean;
  query: string;
  data: any[];
  loading?: boolean;
  Params?: string[];
  paramType?: 'params' | 'formData';
  listUrl?: string;
  page?: number;
  pageSize?: number;
  total?: number;
  delete?: string;
  multiple?: any[];
  sort?: (a: any, b: any) => number;
  openEdit?: (row: any) => void;
  qForm?: IObject | any;
  form: IObject | any;
};

export type ItemType = {
  id: number;
  [key: string]: any;
};

export interface IObject<T = any> {
  [key: string]: T;
}

export interface resultOptions extends TableOptions, IObject {
  fetchData: () => void;
  search?: () => void;
  getDataList?: () => void;
  selectionChange?: (val: any) => void;
  pageSizeChangeHandle?: (val: number) => void;
  pageCurrentChangeHandle?: (val: number) => void;
  getDetail?: (row: string, method?: string) => void;
  deleteRowItem?: (row: any) => void;
  editRowItem?: (row?: any) => void;
}

type Evt = {
  oldIndex: number;
  newIndex: number;
};

type HanderOptions = {
  onRow?: (evt: Evt) => void;
  onCol?: (evt: Evt) => void;
};

export const createDTableOptions = (options: HanderOptions = {}, columns?: Ref<any[]>) => {
  const result: any[] = [];

  if (columns) {
    const columnControl = {
      selector: 'thead tr', // add drag support for column
      option: {
        // sortablejs's option
        animation: 150,
        onEnd: (evt: Evt) => {
          let oldCol: Partial<any> = {};
          Object.assign(oldCol, columns.value[evt.oldIndex]);
          columns.value.splice(evt.oldIndex, 1); // 因为新增了数据，所以要移除原来的列的index要在原来的基础上
          columns.value.splice(evt.newIndex, 0, oldCol);
          setTimeout(options?.onCol || (() => {}), 0);
        }
      }
    };

    result.push(columnControl);
  }

  const rowControl = {
    selector: 'tbody', // add drag support for row
    option: {
      // sortablejs's option
      animation: 150,
      onEnd: async (evt: Evt) => {
        await setTimeout(options?.onRow || (() => {}), 0);
        message.success(`Drag the ${evt.oldIndex}th row to ${evt.newIndex}`);
      }
    }
  };
  result.push(rowControl);

  return result;
};
